﻿using MyHome.Server.PluginBase;
using MyHome.Server.PluginManagement;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.ServiceModel;
using System.Threading.Tasks;

namespace MyHome.Server.Net
{
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
    public class Service : IService
    {
        private PluginHost host = new PluginHost();

        public PluginTemplate AddPlugin(PluginTemplate template)
        {
            var plugin = host.AddPlugin(template.PluginType, template.Configuration, template.X, template.Y);
            return new PluginTemplate { Id = plugin.Id, Configuration = plugin.Configuration, Type = plugin.GetType().FullName, PluginType = plugin.PluginType.ToString(), X = plugin.X, Y = plugin.Y };

        }

        public IEnumerable<PluginTemplate> GetPlugins()
        {
            return host.Plugins.Select(p => new PluginTemplate() { Id = p.Id, Configuration = p.Configuration, Type = p.GetType().FullName, PluginType = p.PluginType.ToString(), X = p.X, Y = p.Y });
        }

        public void DeletePlugin(int pluginId)
        {
            host.DeletePlugin(pluginId);
        }

        public IEnumerable<PluginTemplate> UpdatePlugins(IEnumerable<PluginTemplate> plugins)
        {
            var joined = plugins.FullOuterJoin(host.Plugins, (t, p) => t.Id == p.Id).ToList();
            foreach (var tuple in joined)
            {
                var template = tuple.Item1;
                var plugin = tuple.Item2;
                if(plugin == null)
                {
                    // add
                    host.AddPlugin(template.Type, template.Configuration, template.X, template.Y);
                }
                else if(template == null)
                {
                    // delete
                    host.DeletePlugin(plugin.Id);
                }
                else
                {
                    // update
                    host.UpdatePlugin(plugin.Id, template.Configuration, template.X, template.Y);
                }
            }

            return GetPlugins();
        }

        public PluginConnectionTemplate AddPluginConnections(PluginConnectionTemplate template)
        {
            var connection = host.AddPluginConnection(template.InputId, template.OutputId);
            return new PluginConnectionTemplate { Id = connection.Id, InputId = connection.InputId, OutputId = connection.OutputId };
        }

        public IEnumerable<PluginConnectionTemplate> GetPluginConnections()
        {
            return host.PluginConnections.Select(p => new PluginConnectionTemplate() { Id = p.Id, InputId = p.InputId, OutputId = p.OutputId });
        }

        public void DeletePluginConnection(int pluginConnectionId)
        {
            host.DeletePluginConnection(pluginConnectionId);
        }

        public IEnumerable<PluginConnectionTemplate> UpdatePluginConnections(IEnumerable<PluginConnectionTemplate> pluginConnections)
        {
            var joined = pluginConnections.FullOuterJoin(host.PluginConnections, (t, p) => t.Id == p.Id).ToList();
            foreach (var tuple in joined)
            {
                var template = tuple.Item1;
                var pluginConnection = tuple.Item2;
                if (pluginConnection == null)
                {
                    // add
                    host.AddPluginConnection(template.InputId, template.OutputId);
                }
                else if (template == null)
                {
                    // delete
                    host.DeletePluginConnection(pluginConnection.Id);
                }
                else
                {
                    // update
                    host.UpdatePluginConnection(template.Id, template.InputId, template.OutputId);
                }
            }

            return GetPluginConnections();
        }

        public IEnumerable<string> GetPluginTypes()
        {
            return host.PluginTypes.Select(p => p.Key);
        }

        public void StartPlugins()
        {
            Task.WaitAll(host.StartAsync());
        }

        public void StartPlugin(int pluginId)
        {
            Task.WaitAll(host.StartPluginAsync(pluginId));
        }

        public void StopPlugin(int pluginId)
        {
            Task.WaitAll(host.StopPluginAsync(pluginId));
        }

        public void StopPlugins()
        {
            Task.WaitAll(host.StopAsync());
        }

        public void LoadPlugins()
        {
            Task.WaitAll(host.LoadAsync());
        }
    }
}